#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@File ：__init__.py
@Author ：zqy
@Email : zqingy@work@163.com
@note:
"""
import os

from flask import Flask, request, session, g
from flask_cors import CORS
from flask_restx import Api
from sqlalchemy.engine import URL
from werkzeug.exceptions import MethodNotAllowed

from application.config.DatabaseConfig import MysqlConfig, SqlalchemyConfig
from application.config.ServerConfig import ServerConfig
from application.controller.CartController import cart_ns
from application.controller.CategoriesController import category_ns
from application.controller.CouponController import coupon_ns
from application.controller.FavoriteController import favorite_ns
from application.controller.IndexController import other_ns
from application.controller.OrderController import order_ns
from application.controller.PointsController import points_ns
from application.controller.ProductController import product_ns
from application.controller.UserController import user_ns
from application.controller.AddressController import address_ns
from application.enumeration.StatusCodeEnum import StatusCodeEnum
from application.exception.BasicException import BasicException
from application.exception.MethodException import MethodException
from application.exception.TypeException import TypeException
from application.mapper.UserMapper import UserMapper
from application.util.MysqlUtil import mysql_db
from application.util.StringUtil import random_uuid
from application.util.TokenUtil import verify_token, get_user_id

# 创建日志目录（如果不存在）
os.makedirs(name=ServerConfig.log_dir, exist_ok=True)
# 创建Flask实例
app: Flask = Flask(__name__)
# 设置SECRET_KEY密钥，session用
app.config["SECRET_KEY"] = random_uuid()
CORS(app=app)  # 设置允许跨越
# 连接信息（使用URL构造对象，防止有非法字符导致连接出错）
app.config["SQLALCHEMY_DATABASE_URI"] = URL.create(drivername="mysql+pymysql", username=MysqlConfig.username,
                                                   password=MysqlConfig.password, host=MysqlConfig.host,
                                                   port=MysqlConfig.port, database=MysqlConfig.database_name)

if ServerConfig.dev:
    api = Api(app, title="我的接口文档", description="Flask-RESTX 示例", doc="/docs")
else:
    api = Api(app, doc=False)  # 关闭 /swagger 页面

# 配置是否打印SQL语句
app.config["SQLALCHEMY_ECHO"] = SqlalchemyConfig.on_echo

# app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///demo.db'
# app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# 将Flask实例绑定到数据库
mysql_db.init_app(app=app)
# 创建数据表（如果不存在）
with app.app_context():
    # 导入所有待创建的数据表
    from application.model import *

    mysql_db.create_all()

# 异常注册
app.register_error_handler(BasicException, BasicException.exception_handle)
app.register_error_handler(Exception, BasicException.exception_handle)
app.register_error_handler(TypeError, TypeException.exception_handle)
app.register_error_handler(MethodNotAllowed, MethodException.exception_handle)


@app.errorhandler(AssertionError)
def handle_assertion_error(e):
    # 捕获 AssertionError，按你定义的标准返回
    raise BasicException(
        status_code=StatusCodeEnum.VALIDATOR_ERROR.value,
        error_message=str(e)
    )


@app.before_request
def load_logged_in_user():
    if request.path in ["/user/login", "/docs"]:
        return
    elif "swagger" in request.path:
        return
    try:
        # 过滤掉Bearer 前缀
        token: str = request.headers.get(ServerConfig.token_name)
        if "Bearer" in token:
            token = token.split("Bearer ")[1]
        # 验证用户Token
        if not token:
            raise BasicException(status_code=StatusCodeEnum.AUTHORITY_ERROR.value,
                                 error_message="非法访问，请先登录")

        # 存储Token到session
        # session["user"] = get_user_id(token=token)
        session["user"] = verify_token(token=token)
        g.user = UserMapper.get_info_by_id(model_id=session["user"])
        session.permanent = True  # 设置session永久有效，除非被删除
    except IndexError:
        raise BasicException(status_code=StatusCodeEnum.AUTHORITY_ERROR.value, error_message="Token格式错误")
    except AttributeError:
        raise BasicException(status_code=StatusCodeEnum.AUTHORITY_ERROR.value,
                             error_message=f"缺少{ServerConfig.token_name}")



# # 蓝图注册
# app.register_blueprint(IndexController().blue_print, url_prefix="/")
# app.register_blueprint(UserController().blue_print, url_prefix="/user")
api.add_namespace(other_ns)
api.add_namespace(user_ns)
api.add_namespace(product_ns)
api.add_namespace(cart_ns)
api.add_namespace(order_ns)
api.add_namespace(coupon_ns)
api.add_namespace(points_ns)
api.add_namespace(favorite_ns)
api.add_namespace(category_ns)
api.add_namespace(address_ns)
